package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerPool extends Thread{
	
	/**
	 * ServerSocket
	 */
	private ServerSocket serv;
	
	/**
	 * Collection of the Threads; used for recycling used threads
	 */
	private Vector<ServerThread> threads;
	
	/**
	 * Auction- and UserManager
	 */
	private AuctionManager auctions;
	private UserManager users;
	
	/**
	 * Constructor
	 * @param _port
	 */
	public ServerPool(int _port){
		threads = new Vector<ServerThread>();
		auctions = new AuctionManager();
		users = new UserManager();
		try {
			serv = new ServerSocket(_port);
		} catch (IOException e) {
			System.out.println("ERROR @ServerPool(int):"+e.getMessage());
		}
	}
	
	/**
	 * Shutdown Server
	 * 		Shutdown Order:
	 * 			1. Break accept()-Block by ServerSocket.close()
	 * 			2. Each ServerThread must notifiy the Client: Shutdown
	 * 			3. Closing all open connections (autmatically done by Throwing Exception and Finally Block)
	 * 			4. Closing all open Threads
	 * 			5. Ending AuctionTimer
	 * 			6. Terminating ServerPool
	 */
	public void shutdown(){
		try {
			if(serv != null)
				serv.close();
		} catch (IOException e) {
			System.out.println("ERROR @ServerPool.shutdown():"+e.getMessage());
		}
	}
	
	/**
	 * Thread waiting for new incoming Connections
	 */
	public void run(){
		ExecutorService executor = Executors.newCachedThreadPool();
		NotifyService ns = new NotifyService(threads,auctions,users,300);
		ns.setDaemon(true);
		try{
			ns.start();
			while(true){
				Socket s = serv.accept();
				BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
				String login = in.readLine();//reads login
				if(login.startsWith("!login")){ //Pattern: OK; Creates User and gives User and UDP Port to ServerThread (along with socket for mandatory messages)
					String screenname = login.split(" ")[1];
					User user = users.getUserByScreenname(screenname);
					if(user == null){
						user = new User(login.split(" ")[1]);//User will be set to "online"
						users.addUser(user);	
					}
					if(user.isOnline()){ //ERR: User already online!
						BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
						out.write("User '"+user.getScreenname()+"' is already online!");
						out.newLine();
						out.flush();
						out.write("#resock"); //Little Tweak which allows me to save some memory
						out.newLine();
						out.flush();
						out.close();
					}
					else{
						user.goOnline();
						int pUDP = Integer.parseInt(login.split(" ")[2]);//UDP Port is the last part of the transmission
						threads.add(new ServerThread(s, auctions, users, user, pUDP));
						executor.execute(threads.lastElement());
					}
				}
				else if(login.startsWith("!end")){
					BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
					out.write("#stop");
					out.newLine();
					out.flush();
					out.close();
				}
				else{
					BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
					out.write("You have to log in first!");
					out.newLine();
					out.flush();
					out.write("#resock"); //Little Tweak which allows me to save some memory
					out.newLine();
					out.flush();
					out.close();
				}
			}
		}catch(IOException ioe){ //ServerSocket.close() happens to throw this Exception to jump out of the Loop
			System.out.println("SERVER SHUTDOWN ORDERED!");
		}catch(Exception e){
			System.out.println("ERROR @ServerPool.run():"+e.getMessage());
		}
		finally{ //Destroy Ressources not destroyed until now
			ns.shutdown(); //Stops NotifyService
			for(ServerThread st : threads){
				if(st.isActive()){
					st.shutdown();
				}
			}
			//executor.shutdownNow();
			executor.shutdown();
			//while(!executor.isTerminated());//Waiting for the Threads to die/stop their order
			System.out.println("OFFLINE");
		}
	}

}
